package com.sec.android.app.myfiles.module.local.file;

import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.format.Formatter;
import android.util.SparseArray;
import android.view.View;
import android.widget.TextView;

import com.sec.android.app.myfiles.R;
import com.sec.android.app.myfiles.activity.FileListActivity;
import com.sec.android.app.myfiles.facade.MyFilesFacade;
import com.sec.android.app.myfiles.facade.cmd.CopyMoveCmd;
import com.sec.android.app.myfiles.feature.DragAndDropMgr;
import com.sec.android.app.myfiles.feature.PrivateModeMgr;
import com.sec.android.app.myfiles.fragment.home.HomeFragment;
import com.sec.android.app.myfiles.fragment.home.HomeFragmentItem;
import com.sec.android.app.myfiles.info.AppConstants;
import com.sec.android.app.myfiles.info.AppFeatures;
import com.sec.android.app.myfiles.listener.ListenerMgr;
import com.sec.android.app.myfiles.listener.SystemBroadcastReceiver;
import com.sec.android.app.myfiles.listener.SystemBroadcastReceiver.OnMediaMounted;
import com.sec.android.app.myfiles.listener.SystemBroadcastReceiver.OnMediaScanStart;
import com.sec.android.app.myfiles.listener.SystemBroadcastReceiver.OnMediaUnmounted;
import com.sec.android.app.myfiles.log.Log;
import com.sec.android.app.myfiles.module.abstraction.FileRecord;
import com.sec.android.app.myfiles.module.abstraction.FileRecord.StorageType;
import com.sec.android.app.myfiles.navigation.NavigationInfo;
import com.sec.android.app.myfiles.navigation.NavigationInfo.NavigationMode;
import com.sec.android.app.myfiles.navigation.NavigationManager;
import com.sec.android.app.myfiles.util.FileUtils;
import com.sec.android.app.myfiles.util.StorageMonitor;
import com.sec.android.app.myfiles.util.StorageMonitor.iStorageType;
import com.sec.android.app.myfiles.util.UiUtils;

import java.util.ArrayList;

public class LocalFileHomeItem extends HomeFragmentItem implements OnMediaMounted, OnMediaUnmounted, OnMediaScanStart {

    private static final long STORAGE_UPDATE_DELAY = 100;

    private SparseArray<HomeItemInfo> mItemInfoMap;
    private ListenerMgr mListenerMgr;
    private UpdateSizeHandler mUpdateSizeHandler;
    private TextView mStorageHeader;
    private NavigationMode mCurNavigationMode;
    private DragAndDropMgr mDragDrop;
    private NavigationManager mNavigationMgr;
    private NavigationInfo mCurInfo;

    public LocalFileHomeItem(Context context, HomeFragment fragment) {
        super(context, fragment);
        mListenerMgr = new ListenerMgr();
        mListenerMgr.addListener(new SystemBroadcastReceiver(mContext, this, ListenerMgr.LifeCycle.CREATE, ListenerMgr.LifeCycle.DESTROY));
        mListenerMgr.notifyCreate();
    }

    @Override
    protected void setListItem() {
        mCurNavigationMode = mFragment.getNavigationInfo().getNavigationMode();
        if (mItemInfoMap == null) {
            mItemInfoMap = new SparseArray<>();
        }
        mDragDrop = new DragAndDropMgr(mFragment, StorageType.Home);
        mStorageHeader = (TextView) mRootView.findViewById(R.id.home_storage_header);
        if (mStorageHeader != null) {
            setViewVisibility(mStorageHeader, View.VISIBLE);
            if (AppFeatures.isTablet()) {
                mStorageHeader.setText(mContext.getString(R.string.tablet));
            } else {
                mStorageHeader.setText(mContext.getString(R.string.phone));
            }
        }
        mNavigationMgr = NavigationManager.getInstance(mFragment.getProcessId());
        mCurInfo = mNavigationMgr.getCurInfo();
        checkDeviceStorage();
        checkSdCard(R.id.sd_card_stub, R.id.sd_card, R.drawable.my_files_ic_storage, R.string.sd_card);
        checkPrivateMode();
        checkUsbStorage();
        setItemEnabled(mIsEnabled);
    }

    protected boolean checkDeviceStorage() {
        boolean bRet = false;
        HomeItemInfo item = mItemInfoMap.get(iStorageType.INTERNAL);
        if (isDeviceStorageAvailable(mCurInfo)) {
            if (item == null) {
                FileRecord record = FileRecord.createFileRecord(StorageType.Local, AppConstants.StoragePath.INTERNAL_ROOT);
                HomeItemClickListener onclick = new HomeItemClickListener(record, "Local storage-Device storage");
                item = new HomeItemInfo(0, R.id.device_storage, R.drawable.my_files_ic_phonestorage,
                        R.color.home_icon_device_storage_color, 0, UiUtils.getInternalStorageRootResId(), onclick);
                ensureFreeSize(iStorageType.INTERNAL);
                if (!mItemList.contains(item)) {
                    mItemList.add(item);
                }

                FileRecord focusRecord = getFocusedItem();
                if (focusRecord == null
                        && !(!AppFeatures.isTabletUIMode() && ((FileListActivity) mFragment.getActivity()).isSearchViewExpanded())) {
                    item.itemView.requestFocus();
                }

                mItemInfoMap.put(iStorageType.INTERNAL, item);
                mDragDrop.attachDragListenerToView(item.itemView);

                bRet = true;
            }
        } else {
            if (item != null) {
                setViewVisibility(item.itemView, View.GONE);
            } else {
                View view = mRootView.findViewById(R.id.device_storage);
                setViewVisibility(view, View.GONE);
            }
        }
        return bRet;
    }

    private boolean isDeviceStorageAvailable(NavigationInfo curInfo) {
        return curInfo == null ||
                curInfo.getNavigationMode() != NavigationMode.Select_optimize_storage_backup_destination;
    }

    protected boolean checkSdCard(int stubId, int viewId, int iconId, int stringId) {
        boolean bRet = false;

        HomeItemInfo item = mItemInfoMap.get(iStorageType.EXTERNAL_SD);

        if (StorageMonitor.isExternalStorageAvailable(mCurInfo, mContext)) {
            if (StorageMonitor.isSdCardMounted() || AppFeatures.SUPPORT_SD_CARD) {
                FileRecord record = FileRecord.createFileRecord(StorageType.Local, StorageMonitor.getExtSDCardPath());
                if (item == null) {
                    HomeItemClickListener onclick = new HomeItemClickListener(record, null);
                    item = new HomeItemInfo(stubId, viewId, iconId, R.color.home_icon_sd_card_color, 0, stringId, onclick);
                    mItemInfoMap.put(iStorageType.EXTERNAL_SD, item);
                } else {
                    item.onClickListener.setFileRecord(record);
                    setViewVisibility(item.itemView, View.VISIBLE);
                }

                if (!mItemList.contains(item)) {
                    mItemList.add(item);
                }

                if (StorageMonitor.isSdCardMounted()) {
                    ensureFreeSize(iStorageType.EXTERNAL_SD);
                } else if (AppFeatures.SUPPORT_SD_CARD) {
                    TextView sizeView = (TextView) item.itemView.findViewById(R.id.home_list_item_text_second);
                    if (sizeView != null) {
                        sizeView.setText(R.string.not_inserted);
                    }
                }

                View divider = item.itemView.findViewById(R.id.divider);
                setViewVisibility(divider, isDeviceStorageAvailable(mCurInfo) ? View.VISIBLE : View.GONE);

                mDragDrop.attachDragListenerToView(item.itemView);

                bRet = true;
            } else {
                if (item != null) {
                    setViewVisibility(item.itemView, View.GONE);
                }
            }
        } else {
            if (item != null) {
                setViewVisibility(item.itemView, View.GONE);
            }
        }

        return bRet;
    }

    private void updateSdCardEnabled() {
        if (mCurInfo != null && mCurInfo.isSelectDestination() && !StorageMonitor.isSdCardMounted()) {
            HomeItemInfo item = mItemInfoMap.get(iStorageType.EXTERNAL_SD);
            if (item != null) {
                setChildItemEnabled(item.itemView, false);
            }
        }
    }

    protected boolean checkPrivateMode() {
        boolean bRet = false;
        HomeItemInfo item = mItemInfoMap.get(iStorageType.EXTERNAL_PRIVATE_MODE);

        if (PrivateModeMgr.getInstance(mContext).isEnabled()) {
            if (item == null) {
                FileRecord record = FileRecord.createFileRecord(StorageType.Local, PrivateModeMgr.getInstance(mContext).getRootDir());
                HomeItemClickListener onclick = new HomeItemClickListener(record, "Local storage-Private mode");
                item = new HomeItemInfo(R.id.private_storage_stub, R.id.private_storage, R.drawable.my_files_ic_personalpage,
                        R.color.home_icon_device_storage_color, 0, R.string.private_storage, onclick);
                mItemInfoMap.put(iStorageType.EXTERNAL_PRIVATE_MODE, item);
            } else {
                setViewVisibility(item.itemView, View.VISIBLE);
            }
            if (!mItemList.contains(item)) {
                mItemList.add(item);
            }
            mDragDrop.attachDragListenerToView(item.itemView);
            TextView sizeView = (TextView) item.itemView.findViewById(R.id.home_list_item_text_second);
            setViewVisibility(sizeView, TextView.GONE);
            bRet = true;
        } else {
            if (item != null) {
                setViewVisibility(item.itemView, View.GONE);
            }
        }

        if (item != null && mCurInfo != null) {
            if (mCurInfo.isRemoveFromPrivate() || (mNavigationMgr.isFromPrivateBox() && mCurInfo.getNavigationMode() == NavigationMode.Pick_files)
                    || mCurInfo.isCreateDocument() || mCurInfo.getNavigationMode() == NavigationMode.Select_optimize_storage_backup_destination) {
                mItemList.remove(item);
                setViewVisibility(item.itemView, View.GONE);
                bRet = false;
            }
        }
        return bRet;
    }

    private HomeUsbItemInfo getHomeUsbItemInfo(int stubId, int viewId, String usbName, HomeItemClickListener onclick) {
        HomeUsbItemInfo item;
        if (StorageMonitor.isSSDPowerPacked(mContext)) {
            item = new HomeUsbItemInfo(stubId, viewId, R.drawable.myfiles_ic_ssd_powerpack, R.color.home_icon_ssd_power_pack_color, usbName, onclick);
        } else {
            item = new HomeUsbItemInfo(stubId, viewId, R.drawable.my_files_ic_usb, R.color.home_icon_usb_storage_color, usbName, onclick);
        }
        return item;
    }

    protected boolean checkUsbStorage() {
        boolean bRet = false;
        HomeItemInfo item;
        if (StorageMonitor.isExternalStorageAvailable(mCurInfo, mContext)) {
            for (int usbDriveType = StorageMonitor.iStorageType.EXTERNAL_USB_DRIVE_A; usbDriveType <= StorageMonitor.iStorageType.EXTERNAL_USB_DRIVE_F; usbDriveType++) {
                int viewId = getUsbStorageViewResId(usbDriveType);
                item = mItemInfoMap.get(usbDriveType);
                if (StorageMonitor.isUsbStorageMounted(usbDriveType)) {
                    String usbName = StorageMonitor.getUsbStorageName(mContext, usbDriveType);
                    if (item == null || !item.getDisplayText().equals(usbName)) {
                        if (item != null) {
                            mItemList.remove(item);
                            setViewVisibility(item.itemView, View.GONE);
                            mItemInfoMap.remove(usbDriveType);
                        }
                        int stubId = getUsbStorageViewStubResId(usbDriveType);
                        FileRecord record = FileRecord.createFileRecord(StorageType.Local, StorageMonitor.getUsbStoragePath(usbDriveType));
                        HomeItemClickListener onclick = new HomeItemClickListener(record, null);
                        item = getHomeUsbItemInfo(stubId, viewId, usbName, onclick);
                        mItemInfoMap.put(usbDriveType, item);
                    } else {
                        setViewVisibility(item.itemView, View.VISIBLE);
                    }
                    ensureFreeSize(usbDriveType);
                    if (!mItemList.contains(item)) {
                        mItemList.add(item);
                    }
                    mDragDrop.attachDragListenerToView(item.itemView);
                } else {
                    if (item != null) {
                        mItemList.remove(item);
                        setViewVisibility(item.itemView, View.GONE);
                        mItemInfoMap.remove(usbDriveType);
                    }
                }
            }
        }

        return bRet;
    }

    private int getUsbStorageViewResId(int storageType) {
        switch (storageType) {
            case iStorageType.EXTERNAL_USB_DRIVE_A:
                return R.id.usb_storage_a;
            case iStorageType.EXTERNAL_USB_DRIVE_B:
                return R.id.usb_storage_b;
            case iStorageType.EXTERNAL_USB_DRIVE_C:
                return R.id.usb_storage_c;
            case iStorageType.EXTERNAL_USB_DRIVE_D:
                return R.id.usb_storage_d;
            case iStorageType.EXTERNAL_USB_DRIVE_E:
                return R.id.usb_storage_e;
            case iStorageType.EXTERNAL_USB_DRIVE_F:
                return R.id.usb_storage_f;
            default:
                throw new IllegalArgumentException("wrong storage type: " + storageType);
        }
    }

    private int getUsbStorageViewStubResId(int storageType) {
        switch (storageType) {
            case iStorageType.EXTERNAL_USB_DRIVE_A:
                return R.id.usb_storage_a_stub;
            case iStorageType.EXTERNAL_USB_DRIVE_B:
                return R.id.usb_storage_b_stub;
            case iStorageType.EXTERNAL_USB_DRIVE_C:
                return R.id.usb_storage_c_stub;
            case iStorageType.EXTERNAL_USB_DRIVE_D:
                return R.id.usb_storage_d_stub;
            case iStorageType.EXTERNAL_USB_DRIVE_E:
                return R.id.usb_storage_e_stub;
            case iStorageType.EXTERNAL_USB_DRIVE_F:
                return R.id.usb_storage_f_stub;
            default:
                throw new IllegalArgumentException("wrong storage type: " + storageType);
        }
    }

    private void updateHomeItem() {
        setListItem();
        setItemView();
    }

    @Override
    protected void _onResume() {
        mListenerMgr.notifyResume();
        updateStorageUsage();
        setContentDescription(mStorageHeader, R.string.phone);
    }

    private void updateStorageUsage() {
        updateStorageUsage(iStorageType.INTERNAL);
        if (StorageMonitor.isSdCardMounted()) {
            updateStorageUsage(iStorageType.EXTERNAL_SD);
        }
        if (StorageMonitor.isUsbStorageMounted()) {
            for (int usbDriveType = StorageMonitor.iStorageType.EXTERNAL_USB_DRIVE_A; usbDriveType <= StorageMonitor.iStorageType.EXTERNAL_USB_DRIVE_F; usbDriveType++) {
                if (StorageMonitor.isUsbStorageMounted(usbDriveType)) {
                    updateStorageUsage(usbDriveType);
                }
            }
        }
    }

    private void updateStorageUsage(int storageType) {
        HomeItemInfo itemInfo = mItemInfoMap.get(storageType);
        if (itemInfo != null) {
            if (itemInfo.itemView != null && itemInfo.itemView.getVisibility() == View.VISIBLE) {
                ensureFreeSize(storageType);
            }
        }
    }

    @Override
    protected void _onPause() {
        mListenerMgr.notifyPause();
    }

    @Override
    protected void _onDestroy() {
        mListenerMgr.notifyDestroy();
    }

    @Override
    protected void setItemEnabled(boolean enabled) {
        super.setItemEnabled(enabled);
        if (enabled) {
            updateSdCardEnabled();
        }
    }

    @Override
    protected void setChildItemEnabled(View view, boolean bEnable) {
        super.setChildItemEnabled(view, bEnable);
        if (view != null) {
            View btn = view.findViewById(R.id.home_list_item_text_second);
            if (btn != null) {
                btn.setEnabled(bEnable);
            }
        }
    }

    @Override
    public void onMediaMounted(String path) {
        StorageMonitor.updateSubSystemStorageState(mContext);
        updateHomeItem();
    }

    @Override
    public void onMediaUnmounted(String path) {
        StorageMonitor.updateSubSystemStorageState(mContext);
        updateHomeItem();
        if ((mFragment.getNavigationInfo()).isSelectDestination()) {
            ArrayList<FileRecord> fileRecords = CopyMoveCmd.getSelectedList();
            boolean isPrivateFile = false;
            if (fileRecords != null) {
                for (FileRecord f : fileRecords) {
                    String filePath = f.getFullPath();
                    if (FileUtils.isPrivateFolder(filePath)) {
                        isPrivateFile = true;
                        break;
                    }
                }
            }
            if (isPrivateFile) {
                MyFilesFacade.goHome(mFragment.getProcessId(), null, mContext);
            }
        }
    }


    @Override
    public void onMediaScanStart() {
        ensureFreeSize(iStorageType.INTERNAL, STORAGE_UPDATE_DELAY);
        if (StorageMonitor.isSdCardMounted()) {
            ensureFreeSize(iStorageType.EXTERNAL_SD, STORAGE_UPDATE_DELAY);
        }
    }


    private void ensureFreeSize(int storageType) {
        ensureFreeSize(storageType, 0);
    }

    private void ensureFreeSize(int storageType, long delay) {
        if (mUpdateSizeHandler == null) {
            mUpdateSizeHandler = new UpdateSizeHandler(mItemInfoMap, mCurNavigationMode);
        }
        EnsureFreeSizeThread thread = new EnsureFreeSizeThread(mContext, storageType,
                mCurNavigationMode, mUpdateSizeHandler);
        if (delay > 0) {
            thread.setDelay(delay);
        }
        thread.start();
    }

    private static class EnsureFreeSizeThread extends Thread {
        private final Context mContext;
        private final int mStorageType;
        private final Handler mUpdateSizeHandler;
        private long mDelay = 0L;
        private NavigationMode mNavigationMode;

        public EnsureFreeSizeThread(Context context, int storageType, NavigationMode navigationMode,
                                    Handler updateSizeHandler) {
            mContext = context;
            mStorageType = storageType;
            mNavigationMode = navigationMode;
            mUpdateSizeHandler = updateSizeHandler;
        }

        public void setDelay(long delay) {
            mDelay = delay;
        }

        @Override
        public void run() {
            long newUsedSize;
            long totalSize = 0;
            long freeSpace = -1;
            if (mDelay > 0) {
                try {
                    Thread.sleep(mDelay);
                } catch (InterruptedException e) {
                    Log.e(this, "InterruptedException:" + e.toString());
                }
            }

            if (StorageMonitor.isStorageMounted(mContext, mStorageType)) {
                totalSize = StorageMonitor.getStorageSize(mContext, mStorageType);
                freeSpace = StorageMonitor.getStorageFreeSpace(mContext, mStorageType);
            }

            if (freeSpace != -1 && totalSize != 0) {
                newUsedSize = totalSize - freeSpace;
                mUpdateSizeHandler.removeMessages(mStorageType);
                Message msg = mUpdateSizeHandler.obtainMessage(mStorageType);
                msg.obj = Formatter.formatFileSize(mContext, newUsedSize) + " / " +
                        Formatter.formatFileSize(mContext, totalSize);
                Bundle data = new Bundle();
                data.putLong("free_space", freeSpace);
                if (mNavigationMode == NavigationMode.Select_optimize_storage_backup_destination) {
                    ArrayList<FileRecord> selectedFiles = CopyMoveCmd.getSelectedList();
                    if (selectedFiles != null) {
                        long selectedFilesSize = 0;
                        for (FileRecord rec : selectedFiles) {
                            if (rec != null) {
                                selectedFilesSize += rec.getSize();
                            }
                        }
                        data.putLong("selected_files_size", selectedFilesSize);
                    }
                }
                msg.setData(data);
                mUpdateSizeHandler.sendMessage(msg);
            }
        }
    }

    private static class UpdateSizeHandler extends Handler {
        private final SparseArray<HomeItemInfo> mItemInfoMap;
        private NavigationMode mNavigationMode;

        public UpdateSizeHandler(SparseArray<HomeItemInfo> itemInfoMap, NavigationMode navigationMode) {
            mItemInfoMap = itemInfoMap;
            mNavigationMode = navigationMode;
        }

        @Override
        public void handleMessage(Message msg) {
            HomeItemInfo info = mItemInfoMap.get(msg.what);
            if (info != null) {
                TextView tv = (TextView) info.itemView.findViewById(R.id.home_list_item_text_second);
                if (tv != null) {
                    tv.setText((String) msg.obj);
                    long freeSpace = msg.getData().getLong("free_space");
                    long selectedFilesSize = msg.getData().getLong("selected_files_size");
                    if (mNavigationMode == NavigationMode.Select_optimize_storage_backup_destination) {
                        if (selectedFilesSize > freeSpace) {
                            info.itemView.setEnabled(false);
                            info.itemView.setAlpha(0.4f);
                        } else {
                            info.itemView.setEnabled(true);
                            info.itemView.setAlpha(1.0f);
                        }
                    }
                }
            }
        }
    }
}
